//
//  SegmentDownloadTask.m
//  SegmentDownloadDemo
//
//  Created by gao on 2018/5/29.
//  Copyright © 2018年 gao. All rights reserved.
//
#import "SegmentDownload.h"
#import "SegmentDownloadTask.h"
#import "SegmentDownload.h"
#import <objc/runtime.h>
#import "SegmentDownloadSession.h"
#import "SegmentCategory.h"
#define SegmentBlockSize 1024*1024*10

@implementation SegmentDownloadTask_SubTask
- (void)dealloc
{
    
}
///  解档
- (instancetype)initWithCoder:(NSCoder *)coder
{
    if (self = [super init]) {
        
        unsigned int count = 0;
        Ivar *ivars = class_copyIvarList([self class], &count);
        
        for (NSInteger i=0; i<count; i++) {
            Ivar ivar = ivars[i];
            NSString *name = [[NSString alloc] initWithUTF8String:ivar_getName(ivar)];
            if([name isEqualToString:@"_downloadTask"]) continue;
            id value = [coder decodeObjectForKey:name];
            if(value) [self setValue:value forKey:name];
        }
        
        free(ivars);
        if (!_isFinished) {
            _isDownloading = NO;
//            _downloadTask = [self getDownloadTask];
        }
    }
    return self;
}




///  归档
- (void)encodeWithCoder:(NSCoder *)coder
{
    unsigned int count = 0;
    
    Ivar *ivars = class_copyIvarList([self class], &count);
    
    for (NSInteger i=0; i<count; i++) {
        
        Ivar ivar = ivars[i];
        NSString *name = [[NSString alloc] initWithUTF8String:ivar_getName(ivar)];
        if([name isEqualToString:@"_downloadTask"]) continue;
        id value = [self valueForKey:name];
        if(value) [coder encodeObject:value forKey:name];
    }
    
    free(ivars);
}
-(BOOL)canDownload{
    if (self.isFinished || self.isDownloading) {
        return NO;
    }
//    NSURLSessionTaskState state = self.downloadTask.state;
//    if (self.downloadTask && self.downloadTask.state == NSURLSessionTaskStateRunning) {
//        return NO;
//    }
    return YES;
}
-(BOOL)isFinished{
    
    return _isFinished;
}
#pragma mark --检查下载是否完成
-(BOOL)detectDownloadSubTaskIsFinished{
    if (_isFinished) {
        return YES;
    }
    return YES;
}
-(NSArray *)getTmpPaths{
    NSMutableArray *tmpPaths = [NSMutableArray new];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (self.tempPath.length >0 && [fileManager fileExistsAtPath:self.tempPath]) {
        [tmpPaths addObject:self.tempPath];
    }
    else{
        self.tempPath = nil;
    }
    if (self.tempPath.length > 0) {
//        NSString *downloadPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, true).firstObject;
//        NSString *bundleId = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"];
//        //1. 系统正在下载的文件tmp文件存储路径和部分异常的tmp文件(回调失败)
//        downloadPath = [downloadPath stringByAppendingPathComponent: [NSString stringWithFormat:@"/com.apple.nsurlsessiond/Downloads/%@/", bundleId]];
//        downloadPath = [downloadPath stringByAppendingPathComponent:self.tmpName];
//        if([fileManager fileExistsAtPath:downloadPath]) [tmpPaths addObject:downloadPath];
//
//        //2. 暂停下载后，系统从 downloadPath 目录移动到此
//        NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:task.tmpName];
//        if([fileManager fileExistsAtPath:tmpPath]) [tmpPaths addObject:tmpPath];
    }
    return nil;
}
-(NSURLSessionDownloadTask *)getDownloadTask{
    if (self.endBytesOffset == 0) {
        return nil;
    }
    NSString *range=[NSString stringWithFormat:@"bytes=%ld-%ld", self.startBytesOffset, self.endBytesOffset];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.downloadURL];
    [request setValue:range forHTTPHeaderField:@"Range"];
    NSURLSessionDownloadTask *task = [[SegmentDownloadSession session] downloadTaskWithRequest:request];
    task.taskDescription = [NSString stringWithFormat:@"%@_*_*_%ld",self.downloadURL.absoluteString,self.subTaskIndex];
    return task;
}
-(NSString *)description{
    return [NSString stringWithFormat:@"downloadURL:%@ isFinished:%d downloadState:%ld downloadBytes:%ld message:%@ startBytesOffset:%ld endBytesOffset:%ld ",self.downloadURL.absoluteString,self.isFinished,(long)self.downloadTask.state,self.downloadBytes,self.message,(long)self.startBytesOffset,self.endBytesOffset];
}
@end
@interface SegmentDownloadTask()
@property(nonatomic,strong)NSFileHandle *fileHandle;
@property(nonatomic,strong)NSDate *preDate;
@property(nonatomic,assign)NSInteger preDownloadedBytes;
@property(nonatomic,strong)NSTimer *timer;

@end
@implementation SegmentDownloadTask
- (void)dealloc
{
    
}
#pragma mark - private

///  解档
- (instancetype)initWithCoder:(NSCoder *)coder
{
    if (self = [super init]) {
        
        unsigned int count = 0;
        Ivar *ivars = class_copyIvarList([self class], &count);
        
        for (NSInteger i=0; i<count; i++) {
            Ivar ivar = ivars[i];
            NSString *name = [[NSString alloc] initWithUTF8String:ivar_getName(ivar)];
            if([name isEqualToString:@"_fileHandle"]||[name isEqualToString:@"_timer"]) continue;
            id value = [coder decodeObjectForKey:name];
            if(value) [self setValue:value forKey:name];
        }
        
        free(ivars);
    }
    return self;
}




///  归档
- (void)encodeWithCoder:(NSCoder *)coder
{
    unsigned int count = 0;
    
    Ivar *ivars = class_copyIvarList([self class], &count);
    
    for (NSInteger i=0; i<count; i++) {
        
        Ivar ivar = ivars[i];
        NSString *name = [[NSString alloc] initWithUTF8String:ivar_getName(ivar)];
        if([name isEqualToString:@"_fileHandle"]||[name isEqualToString:@"_timer"]) continue;
        id value = [self valueForKey:name];
        if(value) [coder encodeObject:value forKey:name];
    }
    
    free(ivars);
}

-(instancetype)initWithURL:(NSURL*)URL {
    return [self initWithURL:URL fileTotalBytes:0];

}
-(instancetype)initWithURL:(NSURL*)URL fileTotalBytes:(NSInteger)fileTotalBytes{
    if (self = [super init]) {
        self.downloadURL = URL;
        self.subTaskArray = [NSMutableArray new];
        self.uniqueIdentifier = URL.absoluteString;
        self.fileTotalBytes = fileTotalBytes;
        if (self.fileTotalBytes == 0) {
            [self getFileTotalLength];
        }        
    }
    return self;
}


-(void)initDownloadSubTask{
    if (self.subTaskArray.count == 0) {
        if (self.fileTotalBytes == 0) {
            [self getFileTotalLength];
        }
        else{
            NSInteger currntDownloadStartOffset = 0;
            NSInteger index = 0;
            while (currntDownloadStartOffset < self.fileTotalBytes) {
                long long startOffset = currntDownloadStartOffset;
                long long endOffset = currntDownloadStartOffset + SegmentBlockSize;
                if (endOffset > self.fileTotalBytes) {
                    endOffset = self.fileTotalBytes-1;
                    currntDownloadStartOffset = self.fileTotalBytes;
                }
                else{
                    currntDownloadStartOffset = endOffset;
                }
                SegmentDownloadTask_SubTask *subTask = [SegmentDownloadTask_SubTask new];
                subTask.startBytesOffset = startOffset;
                subTask.endBytesOffset = endOffset;
                subTask.subTaskIndex = index;
                subTask.downloadURL = self.downloadURL;
                
                subTask.downloadTask = [subTask getDownloadTask];
                [self.subTaskArray addObject:subTask];
                index++;
            }

        }

        
    }

}
-(BOOL)checkDownloadTaskIsFinished{
    //检查 是否全部下载完成
    BOOL isDownloadFinished  = YES;
    for (SegmentDownloadTask_SubTask *subTask in self.subTaskArray) {
        if (subTask.isFinished == NO) {
            isDownloadFinished = NO;
            break;
        }
    }
    if (isDownloadFinished) {
        [self stopTimer];
        [[NSNotificationCenter defaultCenter]postNotificationName:@"localPushNotification" object:[NSString stringWithFormat:@"%@下载完成了",[self.downloadURL.absoluteString lastPathComponent]]];
        //全部下载完成
        //检查整个文件下载是否完整
//        NSString *filePath = [self downloadFilePath];
//        NSData *fileData = [[NSData alloc]initWithContentsOfFile:filePath];
//        if (fileData.length == self.fileTotalBytes) {
            [SegmentDownload updateDownloadTask:self status:kDownloadTaskStatusFinished];
//        }
//        else{
//            NSLog(@"Error !!! File size is wrong");
//        }
        
    }
    return isDownloadFinished;
}
#pragma mark --请求文件大小
-(void)getFileTotalLength{
    NSLog(@"request download file size");
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.downloadURL];
    request.HTTPMethod = @"HEAD";
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            NSHTTPURLResponse *tmpResponse = (NSHTTPURLResponse *)response;
            NSLog(@"allHeaderFields:%@", tmpResponse.allHeaderFields);
        }
        NSInteger fileTotalLength = response.expectedContentLength;
        if (fileTotalLength != 0) {
            self.fileTotalBytes = fileTotalLength;
            [self initDownloadSubTask];
            [SegmentDownload downloaderStartWork];
        }
        else{
            [self getFileTotalLength];
        }
    }];
    [dataTask resume];
}
-(void)subTask:(SegmentDownloadTask_SubTask *)subTask updateDownloadBytes:(NSInteger)downloadBytes{
    subTask.downloadBytes = downloadBytes;
    
    //计算下载百分比
    NSInteger currentDownloadBytes = 0;
    for (SegmentDownloadTask_SubTask *sub_task in self.subTaskArray) {
        currentDownloadBytes += sub_task.downloadBytes;
    }
    self.downloadBytes = currentDownloadBytes;

    self.progress = (float)currentDownloadBytes / (float)self.fileTotalBytes;
    id<SegmentDownloadProtocol>receiver = [SegmentDownload getReceiverWithDownloadTask:self];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [receiver updateDownloadTaskProgress:self.progress];
            [receiver updateDownloadTaskDownloadSize:self.downloadBytes totalSize:self.fileTotalBytes];
        });
    });
    
    if (receiver ) {
        if (!self.timer) {
            [self startTimer];
        }
    }
    else{
        [self stopTimer];
    }
//    NSLog(@"%.2f",self.progress);
}
-(void)subTask:(SegmentDownloadTask_SubTask *)subTask downloadFinished:(NSData *)data{
    subTask.isDownloading = NO;
    subTask.downloadBytes = data.length;
    //检查是否下载完整
    if (subTask.endBytesOffset - subTask.startBytesOffset + 1 == data.length) {
        subTask.isFinished = YES;
    }
    else{
        subTask.message = @"下载数据不完整";
    }
    
    
    [SegmentDownload saveDownloadData];
    
    [self.fileHandle seekToFileOffset:subTask.startBytesOffset];
    [self.fileHandle writeData:data];
    
    [self checkDownloadTaskIsFinished];

}

- (void)startTimer {
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateSpeed) userInfo:nil repeats:true];

    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];

}

- (void)stopTimer {
    [self.timer invalidate];
    self.timer = nil;
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            id<SegmentDownloadProtocol>receiver = [SegmentDownload getReceiverWithDownloadTask:self];
            [receiver updateDownloadTaskSpeed:@""];
        });
    });
    
}

-(void)updateSpeed{
    //获取当前时间
    NSDate *currentDate = [NSDate date];
    if (self.preDate != nil) {
        double time = [currentDate timeIntervalSinceDate:self.preDate];
        
        long long speed = (self.downloadBytes - self.preDownloadedBytes) / time;
        if (speed < 0) {
            speed = 0;
        }
        NSString *speedStr = [NSByteCountFormatter stringFromByteCount:speed countStyle:NSByteCountFormatterCountStyleFile];
        
        NSLog(@"%@____",speedStr);
        id<SegmentDownloadProtocol>receiver = [SegmentDownload getReceiverWithDownloadTask:self];
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                [receiver updateDownloadTaskSpeed:[NSString stringWithFormat:@"%@/s",speedStr]];
            });
        });
        
        self.preDate = currentDate;
        self.preDownloadedBytes = self.downloadBytes;
        
    }
    else{
        self.preDate = currentDate;
        self.preDownloadedBytes = self.downloadBytes;
    }
}

#pragma mark -- set get
-(BOOL)canDownload{
    if (self.fileTotalBytes == 0) {
        return NO;
    }
    return YES;
}
-(NSFileHandle *)fileHandle{
    if (_fileHandle == nil) {
        NSString *filePath = [self downloadFilePath];
        
        if (![[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
            [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
        }
        
        _fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
        [_fileHandle truncateFileAtOffset:self.fileTotalBytes];

    }
    
    return _fileHandle;
}
-(NSString *)downloadFilePath{
    return [SegmentDownload filePathWithFileName:[self.downloadURL.absoluteString md5String]];
}

@end
